package com.sfac.springCloudAccount.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sfac.account.entity.User;
import com.sfac.account.entity.UserRole;
import com.sfac.account.vo.UserVo;
import com.sfac.common.vo.Result;
import com.sfac.common.vo.Search;
import com.sfac.springCloudAccount.dao.UserDao;
import com.sfac.springCloudAccount.dao.UserRoleDao;
import com.sfac.springCloudAccount.service.TestFeignClient;
import com.sfac.springCloudAccount.service.UserService;
import com.sfac.springCloudAccount.util.MD5Util;
import com.sfac.test.entity.City;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.vavr.control.Try;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @Description: User Service Impl
 * @author: HymanHu
 * @date: 2021年2月21日
 */
@Service
public class UserServiceImpl implements UserService {

    public static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private TestFeignClient testFeignClient;

    @Override
    public User getUserByUserNameAndPassword(String userName, String password) {
        return userDao.getUserByUserNameAndPassword(userName, MD5Util.getMD5(password));
    }

    @Override
    public User getUserByUserName(String userName) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserName(userName))
                .orElse(Collections.emptyList());
        return users.isEmpty() ? null : users.get(0);
    }

    @Override
    public Result<User> login(User user) {

        User temp = userDao.getUserByUserNameAndPassword(user.getUserName(), user.getPassword());

        if (temp == null) {
            return new Result<User>(Result.ResultStatus.FAILD.code, "用户名或密码错误");
        }

        return new Result<User>(Result.ResultStatus.SUCCESS.code, "Success", temp);

    }


    @Override
    public void logout() {
    }

    @Override
    @Transactional
    public Result<User> insertUser(User user) {
        if (StringUtils.isBlank(user.getUserName()) ||
                StringUtils.isBlank(user.getPassword())) {
            return new Result<User>(Result.ResultStatus.FAILD.code,
                    "User Name or password is null.");
        }

        List<User> users = Optional
                .ofNullable(userDao.getUserByUserName(user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.size() > 0) {
            return new Result<User>(Result.ResultStatus.FAILD.code,
                    "User Name or email is repeat.");
        }

        user.setCreateDate(LocalDateTime.now());
        user.setUpdateDate(LocalDateTime.now());
        user.setPassword(MD5Util.getMD5(user.getPassword()));
        userDao.insertUser(user);
        if (user.getRoles() != null) {
            user.getRoles().stream()
                    .forEach(item -> {
                        userRoleDao.insertUserRole(
                                new UserRole(user.getId(), item.getId()));
                    });
        }
        return new Result<User>(
                Result.ResultStatus.SUCCESS.code, "Insert success", user);
    }

    @Override
    @Transactional
    public Result<User> updateUser(User user) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(
                        user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.stream().filter(item -> item.getId() != user.getId()).count() > 0) {
            return new Result<User>(Result.ResultStatus.FAILD.code,
                    "User Name or email is repeat.");
        }

        userDao.updateUser(user);
        if (user.getRoles() != null && !user.getRoles().isEmpty()) {
            userRoleDao.deleteUserRoleByUserId(user.getId());
            user.getRoles().stream()
                    .forEach(item -> {
                        userRoleDao.insertUserRole(
                                new UserRole(user.getId(), item.getId()));
                    });
        }

        return new Result<User>(Result.ResultStatus.SUCCESS.code,
                "Update success", user);
    }

    @Override
    public User getUserById(int id) {
        return userDao.getUserById(id);
    }

    @Override
    @Transactional
    public Result<Object> deleteUserById(int id) {
        userDao.deleteUserById(id);
        userRoleDao.deleteUserRoleByUserId(id);
        return new Result<Object>(Result.ResultStatus.SUCCESS.code, "Delete success");
    }

    @Override
    public PageInfo<User> getUsersBySearchBean(Search search) {
        search.init();
        PageHelper.startPage(search.getCurrentPage(), search.getPageSize());
        return new PageInfo<User>(Optional
                .ofNullable(userDao.getUsersBySearchVo(search))
                .orElse(Collections.emptyList()));
    }

    @Override
    public List<User> getUsersByKeyWord(String keyword) {
        Search search = new Search();
        search.setKeyword(keyword);
        search.init();
        return Optional.ofNullable(userDao.getUsersBySearchVo(search))
                .orElse(Collections.emptyList());
    }

    @Override
    public UserVo getUserVoByUserIdAndCityId(int userId, int cityId) {
        UserVo userVo = new UserVo();

        User user = userDao.getUserById(userId);
        // 将user对象的属性值copy到userVo
        BeanUtils.copyProperties(user,userVo);

        // 调用 test 微服务，获取城市信息
        //City city = restTemplate.getForObject(
        //        "http://client-test/api/city/{cityId}", City.class,cityId);
        //userVo.setCity(city);

        /**
         * 熔断器策略配置
         * 生产者抛出异常或停掉的情况，都会返回默认值
         * 当一个节点挂掉以后，不会影响其他节点运行
         */
        CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .waitDurationInOpenState(Duration.ofMillis(1000))
                .build();
        CircuitBreaker circuitBreaker = CircuitBreaker.of("circuitBreakerPloy", circuitBreakerConfig);
        //Try<City> circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
        //        circuitBreaker,
        //        () -> restTemplate.getForObject("http://client-test/api/city/{cityId}", City.class, cityId)
        //
        //)).recover(Exception.class, new City());
        //userVo.setCity(circuitBreakerSupplier.get());

        Try<City> circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
                circuitBreaker,
                () -> testFeignClient.getCityByCityId(cityId)

        )).recover(Exception.class, new City());
        userVo.setCity(circuitBreakerSupplier.get());

        return userVo;
    }
}
